const jwt = require('jsonwebtoken');
const crypto = require('crypto');

// 密钥，实际应用中应该存储在更安全的地方或使用环境变量
const JWT_SECRET = 'aicha_secret_key_2024';
// token过期时间（秒）
const TOKEN_EXPIRE = 60 * 60 * 24 * 7; // 7天

/**
 * 生成token
 * @param {Object} payload - 要加密到token中的数据
 * @param {Number} expiresIn - 过期时间（秒）
 * @return {String} token
 */
function generateToken(payload, expiresIn = TOKEN_EXPIRE) {
	return jwt.sign(payload, JWT_SECRET, { expiresIn });
}

/**
 * 验证token
 * @param {String} token - 要验证的token
 * @return {Object} 验证结果，包含解密后的数据或错误信息
 */
function verifyToken(token) {
	try {
		const decoded = jwt.verify(token, JWT_SECRET);
		return {
			valid: true,
			message: '验证成功',
			payload: decoded
		};
	} catch (error) {
		let message = '无效的token';
		if (error.name === 'TokenExpiredError') {
			message = 'token已过期';
		}
		return {
			valid: false,
			message,
			error
		};
	}
}

/**
 * 从请求头中获取token
 * @param {Object} event - 云函数请求事件对象
 * @return {String|null} token或null
 */
function getTokenFromRequest(event) {
	const token = event.headers && (
		event.headers['x-token'] || 
		event.headers['X-Token'] || 
		event.headers['authorization'] || 
		event.headers['Authorization']
	);
	
	if (!token) return null;
	
	// 如果是Bearer token格式，则提取token部分
	if (token.startsWith('Bearer ')) {
		return token.slice(7);
	}
	
	return token;
}

/**
 * 密码加密
 * @param {String} password - 原始密码
 * @param {String} salt - 盐值，如果不提供则自动生成
 * @return {Object} 加密结果，包含hash和salt
 */
function encryptPassword(password, salt) {
	// 如果没有提供盐值，则生成一个
	if (!salt) {
		salt = crypto.randomBytes(16).toString('hex');
	}
	
	// 使用sha256算法，迭代1000次
	const hash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha256').toString('hex');
	
	return {
		hash,
		salt
	};
}

/**
 * 验证密码
 * @param {String} password - 要验证的密码
 * @param {String} hash - 存储的密码哈希
 * @param {String} salt - 存储的盐值
 * @return {Boolean} 验证结果
 */
function verifyPassword(password, hash, salt) {
	const encryptedPassword = encryptPassword(password, salt);
	return encryptedPassword.hash === hash;
}

/**
 * 中间件：验证token并获取用户信息
 * @param {Object} event - 云函数请求事件对象
 * @param {Object} context - 云函数上下文
 * @return {Object} 验证结果，包含用户信息或错误信息
 */
async function authMiddleware(event, context) {
	const token = getTokenFromRequest(event);
	
	if (!token) {
		return {
			auth: false,
			message: '未提供token',
			code: 401
		};
	}
	
	const verifyResult = verifyToken(token);
	
	if (!verifyResult.valid) {
		return {
			auth: false,
			message: verifyResult.message,
			code: 401
		};
	}
	
	// 从token中获取用户ID
	const userId = verifyResult.payload.userId;
	
	// 查询用户信息
	const db = uniCloud.database();
	const userCollection = db.collection('users');
	
	try {
		const userResult = await userCollection.doc(userId).get();
		
		if (userResult.data.length === 0) {
			return {
				auth: false,
				message: '用户不存在',
				code: 401
			};
		}
		
		const user = userResult.data[0];
		
		// 不返回敏感信息
		delete user.password;
		delete user.salt;
		
		return {
			auth: true,
			message: '验证成功',
			code: 200,
			user
		};
	} catch (error) {
		return {
			auth: false,
			message: '验证用户信息失败',
			code: 500,
			error
		};
	}
}

/**
 * 刷新token
 * @param {String} oldToken - 旧的token
 * @return {Object} 刷新结果，包含新token或错误信息
 */
function refreshToken(oldToken) {
	try {
		// 验证旧token
		const verifyResult = verifyToken(oldToken);
		
		// 如果token完全无效（不是仅仅过期），则返回错误
		if (!verifyResult.valid && verifyResult.error.name !== 'TokenExpiredError') {
			return {
				success: false,
				message: '无效的token',
				error: verifyResult.error
			};
		}
		
		// 从旧token中获取payload（即使token过期，payload依然可以解析）
		const payload = jwt.decode(oldToken);
		if (!payload || !payload.userId) {
			return {
				success: false,
				message: '无效的token payload'
			};
		}
		
		// 生成新token，使用相同的userId
		const newToken = generateToken({
			userId: payload.userId
		});
		
		return {
			success: true,
			message: '刷新成功',
			token: newToken
		};
	} catch (error) {
		return {
			success: false,
			message: '刷新token失败',
			error: error.message
		};
	}
}

module.exports = {
	generateToken,
	verifyToken,
	getTokenFromRequest,
	encryptPassword,
	verifyPassword,
	authMiddleware,
	refreshToken
};
